Context: I started playing the piano in 2018 as a complete beginner and I’ve been tracking my practice time for around 2 and a half years. I now decided to put that to good use and see what interesting patterns I might be able to find.
Disclaimer: I am not affiliated with Toggl. I started using it a few years ago because it provided all the functionality I needed and loved its minimalistic design. The standard membership, which I use, is free of charge.
knitr::opts_chunk$set(
echo = FALSE, # show all of the code
tidy = FALSE, # cleaner code printing
size = "small", # smaller code
fig.path = "figs/",# where the figures will end up
out.width = "100%",
message = FALSE,
warning = FALSE
)Based on the level at the time and the difficulty of the piece, we can see that each piece took around 10-30 hours of practice.
Generally, I’ve done pretty well to maintain a high level of consistency with the exception of August/December. This is usually where I tend to take annual leave.
We can see that my practice time was correlated with the consistency, where the average session was much shorter in the months I was away from the piano. There’s also a trend where my practice close to an exam session was significantly higher than any other time of the year. Can you spot in which month I had my exam in 2019? What about the end of 2020?
average practice length per month includes the days in which I did not practice
Similar trends as before are apparent where my average daily session is longer before the exams than any other time in the year and a dip in the months where I usually take most of my annual leave. I really do need to start picking up the pace and get back to where I used to be.
Despite a similar median, we can see that the practice sessions were less likely to be over 80 min after COVID. We can test if this was a significant impact with a t-test.
Given the extremely low p-value, the Shapiro-Wilk normality test implies that the distribution of the data is significantly different from a normal distribution and that we cannot assume the normality. However, we’re working with the entire population dataset for each class and thus, unlike the independence of data, this assumption is not crucial.
| group | statistic | p.value | method |
|---|---|---|---|
| After COVID | 0.9607325 | 3e-07 | Shapiro-Wilk normality test |
| Before COVID | 0.9549818 | 0e+00 | Shapiro-Wilk normality test |
We can see that with a large p value, we should fail to reject the Null hypothesis (Ho) and conclude that we do not have evidence to believe that population variances are not equal and use the equal variances assumption for our t test
| statistic | p.value | df | df.residual |
|---|---|---|---|
| 0.0410026 | 0.8395891 | 1 | 732 |
My practice sessions post-COVID are significantly shorter than those before the pandemic. This might be surprising, given that we were in the lockdown most of the time. However, I’ve been spending my time doing a few other things such as improving my technical skillset with R (this analysis wouldn’t have been possible otherwise) and learning italian.
| .y. | group1 | group2 | n1 | n2 | statistic | df | p | p.signif |
|---|---|---|---|---|---|---|---|---|
| Duration | Before COVID | After COVID | 433 | 301 | 3.319481 | 732 | 0.000947 | *** |
Simplified, ABBRSM grades are a group of 8 exams based on their difficulty (1 - beginner to 8 - advanced). There are also diploma grades but those are extremely advanced, equivalent to university level studies and out of the scope of this analysis.
More information can be found on their official website at https://gb.abrsm.org/en/exam-support/your-guide-to-abrsm-exams/
A further aggregation of ABRSM grades; this is helpful given the very limited dataset within each grade and much easier on the eye. This is an oversimplification but they’re classified as: * 1-5: Beginner (1) * 5-6: Intermediate (2) * 7-8: Advanced (3)
We can spot a trend where the time required to learn a piece of a similar difficulty (ABRSM Grade) decreases as my ability to play the piano increases (as judged by cumulative hours of practice). We should keep this in mind and include it as a variable into our prediction model.
How do we differentiate between pieces that we learn once and those that we come back to repeatedly? Examples could include wanting to improve the playing further, loving it so much we wanted to relearn it, preparing it for a new performance, etc.
As anyone that ever played the piano knows, re-learning a piece, particularly after you “drop” it for a few months/years, results in a much better performance/understanding of the piece. I definitely found that to be true in my experience, particularly with my exam pieces.The downside is that these pieces take longer to learn.
| Project | Duration | Genre | ABRSM | Level | Standard | Length | Experience | Break | Started |
|---|---|---|---|---|---|---|---|---|---|
| Elton John - Rocket man | 47 | Modern | 7 | Advanced | Performance | 4.0 | 1130 | No | 2020-12-08 |
| Schumann - Träumerei | 14 | Romantic | 7 | Advanced | Average | 3.0 | 1087 | No | 2020-11-09 |
| Mozart - Allegro (3rd movement) K282 | 28 | Classical | 6 | Intermediate | Average | 3.3 | 1081 | Yes | 2020-11-05 |
| Ibert - Sérénade sur l’eau | 10 | Modern | 6 | Intermediate | Performance | 1.7 | 1038 | No | 2020-09-24 |
| Kuhlau - Rondo Vivace | 24 | Classical | 6 | Intermediate | Average | 2.2 | 1014 | No | 2020-08-03 |
| C. Hartmann - The little ballerina | 21 | Romantic | 6 | Intermediate | Performance | 2.0 | 998 | No | 2020-07-14 |
| Schumann - Lalling Melody | 5 | Romantic | 1 | Beginner | Average | 1.3 | 981 | No | 2020-06-28 |
| Schumann - Melody | 4 | Romantic | 1 | Beginner | Average | 1.0 | 972 | No | 2020-06-20 |
| Clementi - Sonatina no 3 - Mov 2 | 3 | Classical | 1 | Beginner | Performance | 1.0 | 952 | No | 2020-06-04 |
| Clementi - Sonatina no 3 - Mov 3 | 20 | Classical | 4 | Beginner | Performance | 2.0 | 952 | No | 2020-06-04 |
| Chopin - Waltz in Fm | 27 | Romantic | 6 | Intermediate | Performance | 2.0 | 895 | Yes | 2020-04-18 |
| Clementi - Sonatina no 3 - Mov 1 | 30 | Classical | 4 | Beginner | Performance | 2.7 | 877 | No | 2020-04-07 |
| Schumann - Kinderszenen 1 | 10 | Romantic | 5 | Intermediate | Average | 2.0 | 855 | No | 2020-03-25 |
| Bach - Prelude in G from Cello Suite No 1 | 25 | Baroque | 5 | Intermediate | Average | 2.5 | 788 | No | 2020-02-04 |
| Georg Böhm - Minuet in G | 7 | Baroque | 1 | Beginner | Average | 1.0 | 780 | Yes | 2020-01-27 |
| Bach - Invention 4 in Dm | 21 | Baroque | 5 | Intermediate | Performance | 1.7 | 777 | No | 2020-01-25 |
| Chopin - Contredanse in Gb | 23 | Romantic | 6 | Intermediate | Performance | 2.2 | 762 | No | 2020-01-16 |
| Bach - Minuet in Gm - 115 | 7 | Baroque | 1 | Beginner | Average | 1.3 | 750 | No | 2020-01-07 |
| Bach - Minuet in G - 114 | 4 | Baroque | 1 | Beginner | Average | 2.0 | 726 | No | 2019-12-06 |
| Elton John - Your song (Arr Cornick) | 36 | Modern | 5 | Intermediate | Performance | 3.3 | 713 | No | 2019-11-21 |
| Poulenc - Valse Tyrolienne | 17 | Modern | 5 | Intermediate | Performance | 1.7 | 562 | No | 2019-09-02 |
| Bach - Prelude in Cm - 934 | 25 | Baroque | 5 | Intermediate | Performance | 2.4 | 536 | No | 2019-08-15 |
| Schumann - Volksliedchen | 10 | Romantic | 2 | Beginner | Average | 1.8 | 501 | No | 2019-07-01 |
| Haydn - Andante in A | 39 | Classical | 5 | Intermediate | Average | 2.8 | 468 | Yes | 2019-06-08 |
| Schumann - Remembrance | 34 | Romantic | 5 | Intermediate | Performance | 2.2 | 422 | Yes | 2019-04-28 |
| Bach - Minuet in G - 116 | 8 | Baroque | 1 | Beginner | Average | 2.0 | 361 | Yes | 2019-03-04 |
| Bach - Invention 1 in C | 27 | Baroque | 5 | Intermediate | Performance | 1.7 | 350 | Yes | 2019-02-22 |
| Chopin - Waltz in Am | 26 | Romantic | 4 | Beginner | Performance | 2.5 | 305 | Yes | 2019-01-07 |
Question: How long would it take to learn a piece based on various factors?
Given the very limited data at the advanced level (Grade 7 ABRSM), those two pieces will be removed. One is an extreme outlier as well which will significantly impact our models.
There are no missing values in the modelling dataset following the ETL process.
Let’s use some basic standardisation offered by the caret package such as centering (subtract mean from values) and scaling (divide values by standard deviation).
Given the small size of the dataset, bootstrapping resampling method will be applied.
# set number of clusters
clusters <- 4
# run them all in parallel
cl <- makeCluster(clusters, type = "SOCK")
# register cluster train in paralel
registerDoSNOW(cl)
# train models
model <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
data = model_data,
method = "ranger",
tuneLength = 100,
trControl = train.control)
model2 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
data = model_data,
method = "lmStepAIC",
tuneLength = 100,
trControl = train.control)
model3 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
data = model_data,
method = "lm",
tuneLength = 100,
trControl = train.control)
model4 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
data = model_data,
method = "ridge",
tuneLength = 100,
trControl = train.control)
model5 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
data = model_data,
method = "rf",
tuneLength = 100,
trControl = train.control)
model6 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
data = model_data,
method = "gbm",
tuneLength = 100,
trControl = train.control)
model7 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
data = model_data,
method = "pls",
tuneLength = 100,
trControl = train.control)
# shut the instances of R down
stopCluster(cl)
# compare models
model_list <- list(ranger = model, lmStepAIC = model2, lm = model3, ridge = model4, rf = model5, gbm = model6, pls = model7)
model_comparison <- resamples(model_list)
# learning curves to indicate overfitting and underfitting
# hyper parameters
# https://topepo.github.io/caret/model-training-and-tuning.html#model-training-and-parameter-tuning
# https://topepo.github.io/caret/random-hyperparameter-search.htmlWe chose the Random Forest model as it was the best performing model. It is known as a model which is:
##
## Call:
## summary.resamples(object = model_comparison)
##
## Models: ranger, lmStepAIC, lm, ridge, rf, gbm, pls
## Number of resamples: 25
##
## MAE
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## ranger 3.216848 4.546412 5.226721 5.350732 6.185954 8.074644 0
## lmStepAIC 4.059373 6.035128 6.625829 7.373961 8.656703 12.293508 0
## lm 3.457466 6.104998 6.831580 7.407868 8.107952 16.638647 0
## ridge 3.514506 5.195608 5.904643 5.936369 7.002558 7.751690 10
## rf 2.867137 5.123509 5.592698 5.959335 6.989707 8.722035 0
## gbm 4.593238 6.146348 6.951988 7.261349 8.076775 16.990824 0
## pls 4.460543 5.041959 5.930350 5.848360 6.295627 7.970644 0
##
## RMSE
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## ranger 4.531594 5.821475 6.907062 6.876131 7.614550 10.521156 0
## lmStepAIC 4.678084 7.290730 8.706652 9.067898 10.179064 15.976038 0
## lm 3.979872 8.065115 8.705383 9.404728 10.412562 19.451739 0
## ridge 4.989087 6.206758 6.862180 7.045983 7.854493 8.687658 10
## rf 3.394308 6.640020 7.115649 7.546307 8.461888 11.065527 0
## gbm 5.906910 7.466537 8.041088 8.843606 8.994092 21.377506 0
## pls 5.322380 6.303446 7.096138 7.043631 7.345444 9.624458 0
##
## Rsquared
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## ranger 0.2598148174 0.5915672 0.6861549 0.6395133 0.7899287 0.8801139 0
## lmStepAIC 0.0005882529 0.4001020 0.5735153 0.5051570 0.6597403 0.8997367 0
## lm 0.0019980780 0.2879700 0.5871362 0.4965277 0.6363397 0.8958706 0
## ridge 0.3743315404 0.6559275 0.6807293 0.6828744 0.7764227 0.8621330 10
## rf 0.1341300382 0.5248279 0.6068158 0.5858350 0.7012294 0.8842650 0
## gbm 0.0669333944 0.3848695 0.5685371 0.5338006 0.6661362 0.8728232 0
## pls 0.3579501758 0.6342263 0.6727956 0.6723318 0.7638235 0.8898141 0
Based on our regression model, it does not look like we have significant multicollinearity between the full model variables so we can continue as it is.
| names | VIF |
|---|---|
| ABRSM6 | 4.0 |
| Cumulative_Duration | 3.9 |
| ABRSM5 | 3.5 |
| ABRSM4 | 3.4 |
| GenreClassical | 2.5 |
| Length | 2.4 |
| StandardPerformance | 2.4 |
| BreakNo | 2.1 |
| GenreRomantic | 1.9 |
| ABRSM2 | 1.7 |
| GenreModern | 1.7 |
We can see that the residuals are mostly situated around 0.
Looking at the variability of errors, there is still a tendency to over-predict for pieces that took very little and under-predict for the more difficult ones. There could be two main reasons for this:
We can see that the Random Forest performed significantly better than the Linear Regression model. This isn’t surprising since there might be non-linear trends within the data, and RFs are known to be more accurate.
| estimate | statistic | p.value | parameter | conf.low | conf.high | method | alternative |
|---|---|---|---|---|---|---|---|
| 1.858421 | 3.01994 | 0.0059183 | 24 | 0.5883319 | 3.12851 | One Sample t-test | two.sided |
We can now see that the most important variables seemed to be the length of the piece, my experience prior to starting a piece and time difficulty of the piece. These were also confirmed by the linear regression model.